package com.yyfax.pay.quartz.service.impl;

import java.util.Map;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.apache.commons.lang.NotImplementedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Service;

import com.google.common.collect.Maps;
import com.yyfax.commons.lang.DateUtil;
import com.yyfax.framework.common.Log;
import com.yyfax.framework.spring.ApplicationContextHolder;
import com.yyfax.pay.common.annotation.DepositQueryTaskType;
import com.yyfax.pay.common.constants.QuartzConstant;
import com.yyfax.pay.common.enums.FuiouBusiTypeEnum;
import com.yyfax.pay.common.enums.TaskStateEnum;
import com.yyfax.pay.depository.dao.FuiouQueryTaskDao;
import com.yyfax.pay.depository.domain.FuiouQueryTask;
import com.yyfax.pay.quartz.adapter.DepositQueryHandlerAdapter;
import com.yyfax.pay.quartz.model.vo.TaskResultVO;
import com.yyfax.pay.quartz.service.FuiouDepositQueryService;

@Service
@DependsOn("applicationContextHolder")
public class FuiouDepositQueryServiceImpl implements FuiouDepositQueryService {
	private static final Logger logger = LoggerFactory.getLogger(FuiouDepositQueryServiceImpl.class);
	
	private final Map<FuiouBusiTypeEnum, DepositQueryHandlerAdapter> queryTaskMap = Maps.newHashMap();
	
	@Resource
	private FuiouQueryTaskDao fuiouQueryTaskDao;
	
	@Resource
	private QuartzConstant quartzConstant;
	
	@PostConstruct
	public void init() {
		Map<String, DepositQueryHandlerAdapter> adpaterMap = ApplicationContextHolder.getApplicationContext()
				.getBeansOfType(DepositQueryHandlerAdapter.class);
		for (Object key : adpaterMap.keySet()) {
			DepositQueryHandlerAdapter adpter = adpaterMap.get(key);
			DepositQueryTaskType anno = AnnotationUtils.findAnnotation(adpter.getClass(), DepositQueryTaskType.class);
			if (null != anno) {
				queryTaskMap.put(anno.value(), adpter);
			}
		}
	}

	@Override
	public void executeTask(FuiouQueryTask task) {
		final String op = "FuiouDepositQueryServiceImpl.handle";
		TaskResultVO resultVO = null;
		Throwable dispatchException = null;
		
		logger.info(Log.op(op).msg("【富友存管】【定时查询任务】开始执行").kv("FuiouQueryTask", task).toString());
		
		try {
			try {
				DepositQueryHandlerAdapter handler = getHandler(task.getType());
				// 执行次数+1
				task.setOptNo(task.getOptNo() + 1);
				// 执行业务查询
				resultVO = handler.handle(task);
			} catch (Throwable e) {
				logger.error(Log.op(op).msg("【富友存管】【定时查询任务】执行任务出现异常").kv("id", task.getId()).toString(), e);
				dispatchException = e;
			}

			processDipatchResult(task, resultVO, dispatchException);
		} catch (Exception e) {
			logger.error("【定时任务失败,关闭任务】任务信息:" + task, e);
		}

	}
	
	/**
	 * 执行结果处理
	 * 
	 * @author buyi
	 * @date 2017-05-12 17:16:05
	 * @since v1.0.0
	 * @param task
	 * @param resultVO
	 * @param exception
	 * @throws Exception
	 */
	private void processDipatchResult(FuiouQueryTask task, TaskResultVO resultVO, Throwable exception) throws Exception {
		if (task == null) {
			logger.warn("处理查询结果QueryTaskPO为空");
			return;
		}

		// 更新任务执行信息
		task.setLastTime(DateUtil.getCurrentDateTime());

		// 计算下次执行时间
		task.setNextTime(quartzConstant.getQueryNextTime(task.getOptNo() - 1));

		if (exception != null) {// 如果有异常出现，则直接关闭任务，不再执行
			task.setState(TaskStateEnum.FAILED.getValue());
			task.setRemark(exception.getMessage());

			fuiouQueryTaskDao.updateState(task);
			return;
		}

		/*
		 * 如果没有异常，则判断任务执行响应信息
		 */

		if (resultVO == null) {
			// 若果响应信息为空，更新任务为激活状态，等待下一次执行
			task.setState(TaskStateEnum.ACTIVE.getValue());
			fuiouQueryTaskDao.updateState(task);
			return;
		}

		if (resultVO.isClose()) {
			// 如果响应结果，明确关闭
			task.setState(TaskStateEnum.SUCCESS.getValue());
			task.setRemark(resultVO.getResultMsg());
			fuiouQueryTaskDao.updateState(task);
			return;
		}

		// 如果响应信息没有明确指明是否关闭，则判断是否最大执行次数，以及有效时间
		if (task.getOptNo() >= task.getMaxNo() || (task.getEndTime() != null && task.getEndTime().compareTo(DateUtil.getCurrentDateTime()) <= 0)) {
			task.setState(TaskStateEnum.FAILED.getValue());
			task.setRemark("达到最大查询次数或时间");
			fuiouQueryTaskDao.updateState(task);
		}

		// 如果都不满足，则更新任务状态仍为激活
		task.setState(TaskStateEnum.ACTIVE.getValue());
		fuiouQueryTaskDao.updateState(task);
	}


	/**
	 * 获取主动查询适配实现
	 * 
	 * @author heizq
	 * @date 2017-09-12 13:52:18
	 * @since v1.0.0
	 * @param type
	 * @return
	 */
	private DepositQueryHandlerAdapter getHandler(String type) {
		FuiouBusiTypeEnum pabFuncEnum = FuiouBusiTypeEnum.parse(type);

		if (pabFuncEnum == null) {
			throw new IllegalArgumentException("非法查询类型：" + type);
		}

		DepositQueryHandlerAdapter adapter = queryTaskMap.get(pabFuncEnum);
		if (adapter == null) {
			throw new NotImplementedException("没有找到查询类型：" + pabFuncEnum + "实现类");
		}

		return adapter;
	}

}
